AWS IoT TwinMaker Samples のクッキー工場バージョン3(CookieFactoryV3)を試してみた 〜その2 ダッシュボード操作編〜

AWS IoT TwinMaker Samples のクッキー工場バージョン3(CookieFactoryV3)を試してみた 〜その2 ダッシュボード操作編〜

Clock Icon2024.01.24

こんにちは、CX 事業本部製造ビジネステクノロジー部の若槻です。

前回の記事では、CookieFactoryV3 の環境を構築するところまで行いました。

https://dev.classmethod.jp/articles/aws-iot-twinmaker-samples-cookie-factory-v3-building/

今回は、構築した環境を使用してダッシュボードを実際に操作してみたいと思います。

操作してみる

Web アプリケーションの起動

まずダッシュボードとなる Web アプリケーションをローカル端末上で起動します。

手順にある通りなのですが、

プロジェクトのルートから dashboard ディレクトリに移動し、Vite でアプリケーションを実行します。

# ディレクトリ移動
cd dashboard

# アプリケーションの起動(コマンドの実体は `vite serve --host --https --force`)
npm run dev

起動後のダッシュボードへのアクセス

アプリケーションの起動直後は次のロール選択画面となります。選択できるロールは Spencer(Line Operator)のみです。中央のユーザーアイコンをクリックして選択します。

すると認証中となり、数秒画面が青色になります。

次にロケーション選択画面となります。ただし今回の実装では選択できるロケーションは Bakersville Central のみです。中央のロケーションアイコンをクリックして選択します。

すると IoT TwinMaker の 3D ビューのローティングが開始されます。

その後に 3D ビュー上に Cookie Factory の 3D モデルが表示されます。

生産ラインのステータスの表示

生産ライン上には各種装置のステータスアイコンが表示されています。ステータスは時間経過で変化します。

  • Cookie Former(クッキー成形機)
  • Freezer Tunnel(冷蔵トンネル)
  • Cookie Inspector(クッキー検査装置)
  • Conveyor Vertical(垂直コンベヤー)
  • Conveyor Left Turn(右折コンベヤー)
  • Conveyor Right Turn(左折コンベヤー)
  • Plastic Liner(プラスチックライナー)
  • Box Erector(箱組み立て機)
  • Box Sealer(箱シール貼り機)
  • Labeling Belt(ラベリングベルト)

アイコンをクリックすると、詳細なステータスが表示されます。Box Erector では良品(Good Product)と不良品(Rejected Product)の分毎の数がデータとして確認できます。

良品が増えることによりアイコンのステータスが変化します。

このデータはコンポーネントタイプから取得されます。コンポーネントタイプの実体は、AWS マネジメントコンソールで IoT TwinMaker ワークスペースのエンティティ詳細から確認できます。

そしてコンポーネントタイプのデータはコンソール上でテスト取得できます。下記は Box Erector で対応しているプロパティ(AlarmmessageTemperature および Alarm_status)を時系列(Time-series)データとして取得した様子です。

取得した時系列データは結果から確認可能です。

データ全文
[
  {
    entityPropertyReference: {
      componentName: 'CookieLineComponent',
      externalIdProperty: {
        alarm_key: 'BOX_ERECTOR_142496af-df2e-490e-aed5-2580eaf75e40',
        telemetryAssetId: 'BOX_ERECTOR_142496af-df2e-490e-aed5-2580eaf75e40',
      },
      entityId: 'BOX_ERECTOR_142496af-df2e-490e-aed5-2580eaf75e40',
      propertyName: 'AlarmMessage',
    },
    values: [
      {
        value: {
          stringValue: 'Normal',
        },
        time: '2024-01-24T11:58:30Z',
      },
      {
        value: {
          stringValue: 'Normal',
        },
        time: '2024-01-24T11:58:40Z',
      },
      {
        value: {
          stringValue: 'Normal',
        },
        time: '2024-01-24T11:58:50Z',
      },
      {
        value: {
          stringValue: 'Normal',
        },
        time: '2024-01-24T11:59:00Z',
      },
      {
        value: {
          stringValue: 'Normal',
        },
        time: '2024-01-24T11:59:10Z',
      },
      {
        value: {
          stringValue: 'Low',
        },
        time: '2024-01-24T11:59:20Z',
      },
      {
        value: {
          stringValue: 'Low',
        },
        time: '2024-01-24T11:59:30Z',
      },
      {
        value: {
          stringValue: 'Low',
        },
        time: '2024-01-24T11:59:40Z',
      },
      {
        value: {
          stringValue: 'Low',
        },
        time: '2024-01-24T11:59:50Z',
      },
      {
        value: {
          stringValue: 'Low',
        },
        time: '2024-01-24T12:00:00Z',
      },
      {
        value: {
          stringValue: 'Low',
        },
        time: '2024-01-24T12:00:10Z',
      },
      {
        value: {
          stringValue: 'Low',
        },
        time: '2024-01-24T12:00:20Z',
      },
      {
        value: {
          stringValue: 'Low',
        },
        time: '2024-01-24T12:00:30Z',
      },
      {
        value: {
          stringValue: 'Low',
        },
        time: '2024-01-24T12:00:40Z',
      },
      {
        value: {
          stringValue: 'Low',
        },
        time: '2024-01-24T12:00:50Z',
      },
      {
        value: {
          stringValue: 'Low',
        },
        time: '2024-01-24T12:01:00Z',
      },
      {
        value: {
          stringValue: 'Low',
        },
        time: '2024-01-24T12:01:10Z',
      },
      {
        value: {
          stringValue: 'Normal',
        },
        time: '2024-01-24T12:01:20Z',
      },
      {
        value: {
          stringValue: 'Normal',
        },
        time: '2024-01-24T12:01:30Z',
      },
      {
        value: {
          stringValue: 'Normal',
        },
        time: '2024-01-24T12:01:40Z',
      },
      {
        value: {
          stringValue: 'Normal',
        },
        time: '2024-01-24T12:01:50Z',
      },
      {
        value: {
          stringValue: 'Normal',
        },
        time: '2024-01-24T12:02:00Z',
      },
      {
        value: {
          stringValue: 'Normal',
        },
        time: '2024-01-24T12:02:10Z',
      },
      {
        value: {
          stringValue: 'Normal',
        },
        time: '2024-01-24T12:02:20Z',
      },
      {
        value: {
          stringValue: 'Normal',
        },
        time: '2024-01-24T12:02:30Z',
      },
      {
        value: {
          stringValue: 'Normal',
        },
        time: '2024-01-24T12:02:40Z',
      },
      {
        value: {
          stringValue: 'Normal',
        },
        time: '2024-01-24T12:02:50Z',
      },
      {
        value: {
          stringValue: 'Normal',
        },
        time: '2024-01-24T12:03:00Z',
      },
      {
        value: {
          stringValue: 'Normal',
        },
        time: '2024-01-24T12:03:10Z',
      },
      {
        value: {
          stringValue: 'Normal',
        },
        time: '2024-01-24T12:03:20Z',
      },
    ],
  },
  {
    entityPropertyReference: {
      componentName: 'CookieLineComponent',
      externalIdProperty: {
        alarm_key: 'BOX_ERECTOR_142496af-df2e-490e-aed5-2580eaf75e40',
        telemetryAssetId: 'BOX_ERECTOR_142496af-df2e-490e-aed5-2580eaf75e40',
      },
      entityId: 'BOX_ERECTOR_142496af-df2e-490e-aed5-2580eaf75e40',
      propertyName: 'Temperature',
    },
    values: [
      {
        value: {
          integerValue: 30,
        },
        time: '2024-01-24T11:58:30Z',
      },
      {
        value: {
          integerValue: 48,
        },
        time: '2024-01-24T11:58:40Z',
      },
      {
        value: {
          integerValue: 26,
        },
        time: '2024-01-24T11:58:50Z',
      },
      {
        value: {
          integerValue: 39,
        },
        time: '2024-01-24T11:59:00Z',
      },
      {
        value: {
          integerValue: 24,
        },
        time: '2024-01-24T11:59:10Z',
      },
      {
        value: {
          integerValue: 24,
        },
        time: '2024-01-24T11:59:20Z',
      },
      {
        value: {
          integerValue: 24,
        },
        time: '2024-01-24T11:59:30Z',
      },
      {
        value: {
          integerValue: 24,
        },
        time: '2024-01-24T11:59:40Z',
      },
      {
        value: {
          integerValue: 24,
        },
        time: '2024-01-24T11:59:50Z',
      },
      {
        value: {
          integerValue: 24,
        },
        time: '2024-01-24T12:00:00Z',
      },
      {
        value: {
          integerValue: 24,
        },
        time: '2024-01-24T12:00:10Z',
      },
      {
        value: {
          integerValue: 24,
        },
        time: '2024-01-24T12:00:20Z',
      },
      {
        value: {
          integerValue: 24,
        },
        time: '2024-01-24T12:00:30Z',
      },
      {
        value: {
          integerValue: 24,
        },
        time: '2024-01-24T12:00:40Z',
      },
      {
        value: {
          integerValue: 24,
        },
        time: '2024-01-24T12:00:50Z',
      },
      {
        value: {
          integerValue: 24,
        },
        time: '2024-01-24T12:01:00Z',
      },
      {
        value: {
          integerValue: 24,
        },
        time: '2024-01-24T12:01:10Z',
      },
      {
        value: {
          integerValue: 18,
        },
        time: '2024-01-24T12:01:20Z',
      },
      {
        value: {
          integerValue: 17,
        },
        time: '2024-01-24T12:01:30Z',
      },
      {
        value: {
          integerValue: 44,
        },
        time: '2024-01-24T12:01:40Z',
      },
      {
        value: {
          integerValue: 18,
        },
        time: '2024-01-24T12:01:50Z',
      },
      {
        value: {
          integerValue: 36,
        },
        time: '2024-01-24T12:02:00Z',
      },
      {
        value: {
          integerValue: 24,
        },
        time: '2024-01-24T12:02:10Z',
      },
      {
        value: {
          integerValue: 30,
        },
        time: '2024-01-24T12:02:20Z',
      },
      {
        value: {
          integerValue: 30,
        },
        time: '2024-01-24T12:02:30Z',
      },
      {
        value: {
          integerValue: 30,
        },
        time: '2024-01-24T12:02:40Z',
      },
      {
        value: {
          integerValue: 48,
        },
        time: '2024-01-24T12:02:50Z',
      },
      {
        value: {
          integerValue: 26,
        },
        time: '2024-01-24T12:03:00Z',
      },
      {
        value: {
          integerValue: 39,
        },
        time: '2024-01-24T12:03:10Z',
      },
      {
        value: {
          integerValue: 24,
        },
        time: '2024-01-24T12:03:20Z',
      },
    ],
  },
  {
    entityPropertyReference: {
      componentName: 'CookieLineComponent',
      externalIdProperty: {
        alarm_key: 'BOX_ERECTOR_142496af-df2e-490e-aed5-2580eaf75e40',
        telemetryAssetId: 'BOX_ERECTOR_142496af-df2e-490e-aed5-2580eaf75e40',
      },
      entityId: 'BOX_ERECTOR_142496af-df2e-490e-aed5-2580eaf75e40',
      propertyName: 'alarm_status',
    },
    values: [
      {
        value: {
          stringValue: 'NORMAL',
        },
        time: '2024-01-24T11:58:30Z',
      },
      {
        value: {
          stringValue: 'NORMAL',
        },
        time: '2024-01-24T11:58:40Z',
      },
      {
        value: {
          stringValue: 'NORMAL',
        },
        time: '2024-01-24T11:58:50Z',
      },
      {
        value: {
          stringValue: 'NORMAL',
        },
        time: '2024-01-24T11:59:00Z',
      },
      {
        value: {
          stringValue: 'NORMAL',
        },
        time: '2024-01-24T11:59:10Z',
      },
      {
        value: {
          stringValue: 'ACTIVE',
        },
        time: '2024-01-24T11:59:20Z',
      },
      {
        value: {
          stringValue: 'ACTIVE',
        },
        time: '2024-01-24T11:59:30Z',
      },
      {
        value: {
          stringValue: 'ACTIVE',
        },
        time: '2024-01-24T11:59:40Z',
      },
      {
        value: {
          stringValue: 'ACTIVE',
        },
        time: '2024-01-24T11:59:50Z',
      },
      {
        value: {
          stringValue: 'ACTIVE',
        },
        time: '2024-01-24T12:00:00Z',
      },
      {
        value: {
          stringValue: 'ACTIVE',
        },
        time: '2024-01-24T12:00:10Z',
      },
      {
        value: {
          stringValue: 'ACTIVE',
        },
        time: '2024-01-24T12:00:20Z',
      },
      {
        value: {
          stringValue: 'ACTIVE',
        },
        time: '2024-01-24T12:00:30Z',
      },
      {
        value: {
          stringValue: 'ACTIVE',
        },
        time: '2024-01-24T12:00:40Z',
      },
      {
        value: {
          stringValue: 'ACTIVE',
        },
        time: '2024-01-24T12:00:50Z',
      },
      {
        value: {
          stringValue: 'ACTIVE',
        },
        time: '2024-01-24T12:01:00Z',
      },
      {
        value: {
          stringValue: 'ACTIVE',
        },
        time: '2024-01-24T12:01:10Z',
      },
      {
        value: {
          stringValue: 'NORMAL',
        },
        time: '2024-01-24T12:01:20Z',
      },
      {
        value: {
          stringValue: 'NORMAL',
        },
        time: '2024-01-24T12:01:30Z',
      },
      {
        value: {
          stringValue: 'NORMAL',
        },
        time: '2024-01-24T12:01:40Z',
      },
      {
        value: {
          stringValue: 'NORMAL',
        },
        time: '2024-01-24T12:01:50Z',
      },
      {
        value: {
          stringValue: 'NORMAL',
        },
        time: '2024-01-24T12:02:00Z',
      },
      {
        value: {
          stringValue: 'NORMAL',
        },
        time: '2024-01-24T12:02:10Z',
      },
      {
        value: {
          stringValue: 'NORMAL',
        },
        time: '2024-01-24T12:02:20Z',
      },
      {
        value: {
          stringValue: 'NORMAL',
        },
        time: '2024-01-24T12:02:30Z',
      },
      {
        value: {
          stringValue: 'NORMAL',
        },
        time: '2024-01-24T12:02:40Z',
      },
      {
        value: {
          stringValue: 'NORMAL',
        },
        time: '2024-01-24T12:02:50Z',
      },
      {
        value: {
          stringValue: 'NORMAL',
        },
        time: '2024-01-24T12:03:00Z',
      },
      {
        value: {
          stringValue: 'NORMAL',
        },
        time: '2024-01-24T12:03:10Z',
      },
      {
        value: {
          stringValue: 'NORMAL',
        },
        time: '2024-01-24T12:03:20Z',
      },
    ],
  },
];

ただし、ダッシュボード上で表示されていた良品や不良品などの情報はこのデータには含まれておらず、コンポーネントタイプから取得されたデータが本ダッシュボードでそのまま使われているわけではないようです。

プロセスグラフの表示

画面下部の[Process]をクリックすると、生産ラインの各装置のプロセスグラフが表示されます。

グラフ中のノードが生産ライン上の装置に対応しています。ノードをクリックすると、対応する装置のステータスが表示されます。逆に 3D ビュー上の装置をクリックすると、プロセスグラフのノードがハイライトされます。

このように、3D ビューとプロセスグラフが連動することにより、各装置の関係性、ステータスおよび位置関係を生産管理者は容易に把握することができます。

データのダッシュボード表示

また画面下部の[Dashboard]をクリックすると、生産ライン上で選択中の装置のデータがダッシュボード表示されます。

Cookie Inspector を選択した場合はクッキーの検査写真が確認できます。

ダッシュボードは AWS IoT Application Kit を使って実装されている

さてここまで確認したダッシュボードは非常にリッチなビジュアライズが行われていましたが、これらは AWS IoT Application Kit を使って実装されています。

https://github.com/awslabs/iot-app-kit

AWS IoT Application Kit は AWS IoT のリソースやデータを表示するダッシュボードを簡単に構築するためのキットとして提供されている React Component です。AWS IoT の各種サービスごとに Sub Component が提供されており、下記から IoT TwinMaker の実装方法も確認できます。

https://github.com/awslabs/iot-app-kit/blob/main/docs/GettingStarted.md

この Component をベースにカスタマイズすることにより、既存のアプリケーションに IoT TwinMaker の 3D ビューを組み込んだり、今回紹介したようなリッチなダッシュボードを実装したりすることができます。

トラブルシュート

Cloud9 環境上だと Vite で起動したアプリケーションにアクセスできない

CookieFactoryV3 でのデモ手順の冒頭で、前提条件として Cloud9 環境上でのアプリケーションの実行が推奨されています。

しかし Vite でアプリケーションを起動し、Cloud9 のプレビュー機能でアクセスしようとすると、下記のようなエラーとなりアクセスできませんでした。

Oops
No application seems to be running here!

以前に CookieFactoryV3 でないアプリケーションで試した時は問題無かったのですが、今回は何らかの問題が発生しているようです。

https://dev.classmethod.jp/articles/launching-vite-dev-server-on-aws-cloud9/

よって、本記事でのアプリケーションでの起動はローカル端末上で行いました。

ネクストアクション

次回はいよいよこの V3 のサンプルに下記で紹介されている Amazon Bedrock の実装を追加したいと思います。楽しみですね。

https://aws.amazon.com/blogs/iot/building-an-ai-assistant-for-smart-manufacturing-with-aws-iot-twinmaker-and-amazon-bedrock/

(追記)実際に試してみた内容は以下のブログで紹介しています。

https://dev.classmethod.jp/articles/aws-iot-twinmaker-samples-cookie-factory-v3-ai-assistant-settings/

以上

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.